package com.suray.wcs.service.test.action.checkmap;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.enums.TaskType;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDBServiceImpl;
import com.suray.wcs.service.test.action.checkmap.core.CheckMapGroundCode;
import com.suray.wcs.service.test.action.checkmap.core.GroundCodeContainer;
import com.suray.wcs.service.test.base.BaseThread;
import com.suray.wcs.service.util.WcsUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 地码检测
 */
public class RgvCheckMap extends BaseThread {

    private static TaskDBServiceImpl taskDBService = SpringContextHolder.getBean(TaskDBServiceImpl.class);
    private NodeDBServiceImpl nodeDBService = SpringContextHolder.getBean(NodeDBServiceImpl.class);

    /**
     * 任务路径扫到的条码
     */
    private List<String> path;

    private String lastGroundCode;

    /**
     * 执行任务的小车
     */
    private Rgv rgv;

    /**
     * 任务Id
     */
    private TaskDB taskDB;

    private CheckMapGroundCode mapNode;

    /**
     * 扫到的地码容器
     */
    private GroundCodeContainer actCodes;

    /**
     * 标志的地码容器
     */
    protected GroundCodeContainer standardCodes;

    private boolean isScanEnd;

    public RgvCheckMap(TaskDB taskDB, Rgv rgv, List<Node> nodes) throws RuntimeException {
        super("地码检测任务", 10);

        if (nodes.size() == 0) {
            endThread();
        } else {
            this.rgv = rgv;
            this.taskDB = taskDB;

            isScanEnd = false;

            path = new ArrayList<>();

            mapNode = new CheckMapGroundCode(nodes, rgv.getDirectionStatus());

            standardCodes = new GroundCodeContainer(mapNode.getGroundCodes());
        }
    }

    /**
     * 生成检测任务
     * @param node
     */
    public static void checkMap(Rgv rgv, Node node) {
        WcsUtil.generalTask(rgv.getCurLocation(), node, rgv, TaskType.MOVE_UNLOADED, taskDBService, RgvCheckMap.class);
    }

    @Override
    protected void process() {
        if (isScanEnd) {
            String groundCode = analyzeGroundCode(rgv);
            if (lastGroundCode == null || !lastGroundCode.equals(groundCode)) {
                lastGroundCode = groundCode;
                path.add(groundCode);
            }
            actCodes = new GroundCodeContainer(path);
            checkCode(actCodes, standardCodes);
            endThread();
        } else {
            if (rgv.getGroundCode() != null) {
                String groundCode = analyzeGroundCode(rgv);
                if (lastGroundCode == null || !lastGroundCode.equals(groundCode)) {
                    lastGroundCode = groundCode;
                    LoggerUtil.debug("扫到地码：" + groundCode, this.getClass());
                    path.add(groundCode);
                }
            }
        }
    }

    /**
     * 解析小车当前完整地码
     * @param rgv
     * @return
     */
    private String analyzeGroundCode(Rgv rgv) {
        return rgv.getFullGroundCode();
    }

    /**
     * 检测地码
     * @param actCodes :rgv行驶扫到的地码(需验证的地码)
     * @param standardCodes :rgv行驶的路径应该存在的地码(正确的地码)
     */
    protected void checkCode(GroundCodeContainer actCodes, GroundCodeContainer standardCodes) {
        LoggerUtil.debug("扫到的码:" + WcsUtil.listToString(actCodes.getGroundCodes()), this.getClass());
        LoggerUtil.debug("标准的码:" + WcsUtil.listToString(standardCodes.getGroundCodes()), this.getClass());
        while (true) {
            try {
                LoggerUtil.debug("扫码地码下标：" + actCodes.getCodeIndex() + ", 标准地码下标:" + standardCodes.getCodeIndex(), this.getClass());
                if (standardCodes.isEnd()) {
                    //校验结束
    //                if (!actCodes.isEnd()) {
    //                    String info = "在节点" +
    //                            mapNode.getNode(mapNode.getGroundCodes().get(mapNode.getGroundCodes().size() - 1)) +
    //                            ", 后面检测到多余的地码：" +
    //                            WcsUtil.listToString(actCodes.getLeftGroundCodes());
    //                    LoggerUtil.debug(info, this.getClass());
    //                    WcsUtil.notification(info);
    //                }

                    break;
                } else if (actCodes.isEnd()) {
                    //校验结束
    //                String info = "未检测到地码：" + WcsUtil.mapToString(mapNode.getNodes(standardCodes.getLeftGroundCodes()));
    //                LoggerUtil.debug(info, this.getClass());
    //                WcsUtil.notification(info);
                    break;
                }

                String actCode = actCodes.getGroundCode();
                String standardCode = standardCodes.getGroundCode();
                if (actCode.equals(standardCode)) {
                    //地码匹配
                    LoggerUtil.debug("地码正确:" + actCode, this.getClass());
                    actCodes.nextCode();
                    standardCodes.nextCode();
                } else {
                    //地码不匹配
                    if (standardCodes.contains(actCode)) {
                        //存在扫到的地码，判断可能有丢码
                        lostGroundCode(actCodes, actCode, standardCodes);
                    } else {
                        String preStandardCode = standardCodes.getPreGroundCode();

                        String info = mapNode.getNode(standardCode) + "节点" + standardCode +
                                (preStandardCode == null ? "码前面" :
                                        ("与" + mapNode.getNode(preStandardCode) + "节点" + preStandardCode + "码之间")) +
                                "扫到多余的地码：" + actCode;
                        LoggerUtil.debug(info, this.getClass());
                        WcsUtil.notification(info);
                        actCodes.nextCode();
                    }
                }
            } catch (Exception e) {
                WcsUtil.exceptionLog(e, this.getClass());
            }
        }
    }

    //丢码
    private void lostGroundCode(GroundCodeContainer actCodes, String actCode, GroundCodeContainer standardCodes) {
        int targetIndex = standardCodes.indexOf(actCode);
        if (targetIndex < standardCodes.getCodeIndex()) {
            //地码错误
            LoggerUtil.debug(mapNode.getNode(standardCodes.get(standardCodes.getCodeIndex() - 1)) +
                    "节点，附近有错误的地码，或则前面的地码顺序贴错了：" + actCode, this.getClass());
            WcsUtil.notification(mapNode.getNode(standardCodes.get(standardCodes.getCodeIndex() - 1)) +
                    "节点，附近有错误的地码，或则前面的地码顺序贴错了：" + actCode);
            actCodes.nextCode();
            return;
        }

        if (checkIsCodeReverse(actCodes, actCode, standardCodes)) {
            return;
        }

        if (actCodes.getGroundCodes().size() > (actCodes.getCodeIndex() + 1)) {
            int nextCodeIndex = standardCodes.indexOf(actCodes.get(actCodes.getCodeIndex() + 1));
            //如果nextCodeIndex == -1,下一个码有问题，认为当前的码为正确的
            if (nextCodeIndex != -1) {
                //地码错误
                if (nextCodeIndex < targetIndex) {
                    if (targetIndex == (nextCodeIndex + 1)
                            || targetIndex == (nextCodeIndex + 2)
                            || targetIndex == (nextCodeIndex + 3)) {
                        //如果nextCodeIndex < targetIndex，说明这两个码有一个码有问题
                        String info = mapNode.getNode(standardCodes.get(targetIndex)) +
                                "节点, " + standardCodes.get(targetIndex) + "码，与" +
                                mapNode.getNode(standardCodes.get(nextCodeIndex)) +
                                "节点, " + standardCodes.get(nextCodeIndex) + "码贴反了";
                        LoggerUtil.debug(info, this.getClass());
                        WcsUtil.notification(info);
                        actCodes.nextCode();
                        return;
                    } else if (nextCodeIndex >= standardCodes.getCodeIndex()) {
                        //如果nextCodeIndex < targetIndex，说明这两个码有一个码有问题
                        //说明当前的码贴错了
                        LoggerUtil.debug(mapNode.getNode(standardCodes.get(standardCodes.getCodeIndex() - 1)) +
                                "节点，附近有错误的地码：" + actCode, this.getClass());
                        WcsUtil.notification(mapNode.getNode(standardCodes.get(standardCodes.getCodeIndex() - 1)) + "节点，附近有错误的地码：" + actCode);
                        actCodes.nextCode();
                        return;
                    }
                } else if (nextCodeIndex == targetIndex) {
                    //如果nextCodeIndex == targetIndex，说明这两个码有一个码贴错了
                    LoggerUtil.debug(mapNode.getNode(standardCodes.get(nextCodeIndex)) +
                            "节点，附近贴了相同的地码：" + actCode, this.getClass());
                    WcsUtil.notification(mapNode.getNode(standardCodes.get(nextCodeIndex)) +
                            "节点，附近贴了相同的地码：" + actCode);
                    actCodes.nextCode();
                    return;
                }
            }
        }

//        for (int i = standardCodes.getCodeIndex(); i < targetIndex; i++) {
//            String groundCode = standardCodes.get(i);
//            LoggerUtil.debug(mapNode.getNode(groundCode) + "节点未检测到地码：" + groundCode, this.getClass());
//            WcsUtil.notification(mapNode.getNode(groundCode) + "节点未检测到地码：" + groundCode);
//        }

        actCodes.nextCode();
        standardCodes.setCodeIndex(targetIndex + 1);
    }

    /**
     * 检测码是否贴反
     * @param actCodes
     * @param actCode
     * @param standardCodes
     * @return
     */
    private boolean checkIsCodeReverse(GroundCodeContainer actCodes, String actCode, GroundCodeContainer standardCodes) {
        String aftActCode1 = actCodes.get(actCodes.getCodeIndex() + 1);
        String aftActCode2 = actCodes.get(actCodes.getCodeIndex() + 2);
        String standardCode = standardCodes.getGroundCode();
        String aftStandardCode1 = standardCodes.get(standardCodes.getCodeIndex() + 1);
        String aftStandardCode2 = standardCodes.get(standardCodes.getCodeIndex() + 2);

        if (aftActCode1 == null || aftStandardCode1 == null) {
            return false;
        }

        if (aftStandardCode2 != null) {
            //转弯处漏码判断
            if (actCode.equals(aftStandardCode1) && aftActCode1.equals(aftStandardCode2)) {
                if (standardCode.equals(aftStandardCode2)) {
                    //第一个码与第三个码相同，此时第一个码漏了，不做反码判断
                    actCodes.setCodeIndex(actCodes.getCodeIndex() + 2);
                    standardCodes.setCodeIndex(standardCodes.getCodeIndex() + 3);
                    return true;
                }
            }
        }

        if (aftActCode2 == null || aftStandardCode2 == null) {
            if (actCode.equals(aftStandardCode1) && aftActCode1.equals(standardCode)) {
                //两个码贴反
                String info = mapNode.getNode(actCode) + "节点, " + actCode + "码，与" +
                        mapNode.getNode(aftActCode1) + "节点, " + aftActCode1 + "码贴反了";
                LoggerUtil.debug(info, this.getClass());
                WcsUtil.notification(info);
                actCodes.setCodeIndex(actCodes.getCodeIndex() + 2);
                standardCodes.setCodeIndex(standardCodes.getCodeIndex() + 2);
                return true;
            }
        } else {
            if (actCode.equals(aftStandardCode2) && aftActCode1.equals(aftStandardCode1) &&
                    aftActCode2.equals(standardCode)) {
                //3个码贴反
                String info = mapNode.getNode(actCode) + "节点, " + actCode + "码，与" +
                        mapNode.getNode(aftActCode2) + "节点, " + aftActCode2 + "码贴反了";
                LoggerUtil.debug(info, this.getClass());
                WcsUtil.notification(info);
                actCodes.setCodeIndex(actCodes.getCodeIndex() + 3);
                standardCodes.setCodeIndex(standardCodes.getCodeIndex() + 3);
                return true;
            }
        }

        return false;
    }

    /**
     * 开始分析地码
     */
    public void startAnalyzeGroundCode() {
        isScanEnd = true;
    }

    @Override
    public String toString() {
        return "RgvCheckMap{" +
                ", path=" + WcsUtil.listToString(new ArrayList<>(path)) +
                ", rgv=" + rgv +
                ", taskDB=" + taskDB +
                ", mapNode=" + mapNode +
                '}';
    }
}
